using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.Design;
using System.Collections;
using OpenComposite.EII.Repository;
using System.Windows.Forms;

namespace OpenComposite.EII.Services
{
	public class RepositorySelectionService : OpenComposite.EII.Services.IRepositorySelectionService
	{
		IServiceProvider _serviceProvider;
		IList _selectedItems;

		public event EventHandler SelectionChanging = null;
		public event EventHandler SelectionChanged = null;

		public RepositorySelectionService(IServiceProvider serviceProvider)
		{
			this._serviceProvider = serviceProvider;

			_selectedItems = new ArrayList();

			// we need to know when repository items get added and/or removed
			IRepositoryChangeService changeService = (IRepositoryChangeService)_serviceProvider.GetService(typeof(IRepositoryChangeService));
			changeService.RepositoryAdded += new RepositoryEventHandler(OnRepositoryAdded);
			changeService.RepositoryRemoved += new RepositoryEventHandler(OnRepositoryRemoved);
		}

		public ICollection GetSelectedRepositoryItems()
		{
			return _selectedItems;
		}

		private void OnSelectionChanging(EventArgs e)
		{
			// fire changing event
			if ( SelectionChanging != null ) {
				try {
					SelectionChanging(this, e);
				} catch { }
			}
		}

		private void OnSelectionChanged(EventArgs e)
		{
			// fire changed event
			if ( SelectionChanged != null ) {
				try {
					SelectionChanged(this, e);
				} catch { }
			}
		}

		public object PrimarySelection
		{
			get
			{
				return ( ( _selectedItems != null && _selectedItems.Count > 0 ) ? _selectedItems[0] : null );
			}
		}

		public int SelectionCount
		{
			get
			{
				return _selectedItems.Count;
			}
		}

		public bool GetRepositoryItemSelected(object repositoryItem)
		{
			// is the component in our selected list
			return _selectedItems.Contains(repositoryItem);
		}

		public void SetSelectedRepositoryItems(ICollection repositoryItems, SelectionTypes selectionType)
		{
			// fire changing event
			if ( SelectionChanging != null ) {
				try {
					SelectionChanging(this, EventArgs.Empty);
				} catch { }
			}
			// dont allow an empty collection
			if ( repositoryItems == null || repositoryItems.Count == 0 ) {
				repositoryItems = new ArrayList();
			}
			bool ctrlDown = false, shiftDown = false;
			// we need to know if shift or ctrl is down on clicks 
			if ( ( selectionType & SelectionTypes.Primary ) == SelectionTypes.Primary ) {
				ctrlDown = ( ( Control.ModifierKeys & Keys.Control ) == Keys.Control );
				shiftDown = ( ( Control.ModifierKeys & Keys.Shift ) == Keys.Shift );
			}
			if ( selectionType == SelectionTypes.Replace ) {
				// discard the hold list and go with this one
				_selectedItems = new ArrayList(repositoryItems);
			} else {
				if ( !shiftDown && !ctrlDown && repositoryItems.Count == 1 && !_selectedItems.Contains(repositoryItems) ) {
					_selectedItems.Clear();
				}
				// something was either added to the selection
				// or removed
				IEnumerator ie = repositoryItems.GetEnumerator();
				while ( ie.MoveNext() ) {
					IRepositoryItem item = ie.Current as IRepositoryItem;
					if ( item != null ) {
						if ( ctrlDown || shiftDown ) {
							if ( _selectedItems.Contains(item) ) {
								_selectedItems.Remove(item);
							} else {
								// put it back into the front because it was
								// the last one selected
								_selectedItems.Insert(0, item);
							}
						} else {
							if ( !_selectedItems.Contains(item) ) {
								_selectedItems.Add(item);
							} else {
								_selectedItems.Remove(item);
								_selectedItems.Insert(0, item);
							}
						}
					}
				}
			}
			// fire changed event
			if ( SelectionChanged != null ) {
				try {
					SelectionChanged(this, EventArgs.Empty);
				} catch { }
			}
		}

		public void SetSelectedRepositoryItems(ICollection repositoryItems)
		{
			SetSelectedRepositoryItems(repositoryItems, SelectionTypes.Replace);
		}

		private void OnRepositoryRemoved(object sender, RepositoryEventArgs e)
		{
			if ( e.RepositoryItem is WorkflowField ) return;
			if ( _selectedItems.Contains(e.RepositoryItem) ) {
				// fire changing event
				OnSelectionChanging(EventArgs.Empty);
				// discard RepositoryItem
				_selectedItems.Remove(e.RepositoryItem);
				// fire changed event
				OnSelectionChanged(EventArgs.Empty);
			}
		}

		private void OnRepositoryAdded(object sender, RepositoryEventArgs e)
		{
			// if its not already in the list
			if ( !_selectedItems.Contains(e.RepositoryItem) ) {
				// fire changing event
				OnSelectionChanging(EventArgs.Empty);
				// discard RepositoryItem
				_selectedItems.Add(e.RepositoryItem);
				// fire changed event
				OnSelectionChanged(EventArgs.Empty);
			}
		}
	}
}
